import { Base64 } from 'js-base64'
import crypto from 'crypto-js'
import { ref } from 'vue'
import { getStsToken } from '@/api/oss'

// CDN域名常量
const CDN_HOST = 'https://cdn.keketrtr.top'

/**
 * STS Token 响应式存储
 * @type {import('vue').Ref<any>}
 */
export const stsToken = ref(null)
let refreshTimer = null

/**
 * 获取并设置STS Token，并自动定时刷新
 * @returns {Promise<void>}
 */
export async function fetchAndScheduleStsToken() {
    try {
        const { data: token } = await getStsToken()
        stsToken.value = token
        // 解析过期时间，提前2分钟刷新
        if (token && token.expiration) {
            const expireTime = new Date(token.expiration).getTime()
            const now = Date.now()
            const refreshBefore = 2 * 60 * 1000 // 2分钟
            let timeout = expireTime - now - refreshBefore
            if (timeout < 0) timeout = 10 * 1000 // 如果已过期或快过期，10秒后重试
            if (refreshTimer) clearTimeout(refreshTimer)
            refreshTimer = setTimeout(fetchAndScheduleStsToken, timeout)
        }
    } catch (e) {
        stsToken.value = null
        // 失败后30秒重试
        if (refreshTimer) clearTimeout(refreshTimer)
        refreshTimer = setTimeout(fetchAndScheduleStsToken, 30 * 1000)
    }
}

/**
 * 清理定时器，组件卸载时调用
 */
export function clearStsTokenTimer() {
    if (refreshTimer) clearTimeout(refreshTimer)
}

/**
 * 上传前检查token是否快过期，若快过期则刷新
 * @returns {Promise<void>}
 */
export async function ensureStsTokenValid() {
    if (!stsToken.value || !stsToken.value.expiration) {
        await fetchAndScheduleStsToken()
        return
    }
    const expireTime = new Date(stsToken.value.expiration).getTime()
    const now = Date.now()
    const refreshBefore = 2 * 60 * 1000 // 2分钟
    if (expireTime - now < refreshBefore) {
        await fetchAndScheduleStsToken()
    }
}

/**
 * 计算 OSS 签名
 * @param {string} accessKeySecret - OSS 的 accessKeySecret
 * @param {string} canonicalString - 需要签名的字符串
 * @returns {string} 签名后的字符串
 */
function computeSignature(accessKeySecret, canonicalString) {
    return crypto.enc.Base64.stringify(crypto.HmacSHA1(canonicalString, accessKeySecret));
}

/**
 * 通过uni.uploadFile直传OSS（微信小程序专用）
 * @param {String} filePath 本地临时文件路径
 * @param {String} dir OSS存储目录
 * @returns {Promise<String>} 上传后文件的完整URL
 */
export async function uploadToOSS(filePath, dir = 'uploads') {
    await ensureStsTokenValid()
    if (!stsToken.value) throw new Error('获取OSS直传参数失败')
    const ext = filePath.split('.').pop() || 'jpg'
    const objectKey = `${dir}/${Date.now()}_${Math.random().toString(36).slice(2)}.${ext}`

    const date = new Date();
    date.setHours(date.getHours() + 1);
    const policyText = {
        expiration: date.toISOString(),
        conditions: [
            ["content-length-range", 0, 10 * 1024 * 1024],
        ],
    };
    const policy = Base64.encode(JSON.stringify(policyText))
    const signature = computeSignature(stsToken.value.accessKeySecret, policy)
    const formData = {
        OSSAccessKeyId: stsToken.value.accessKeyId,
        signature,
        policy,
        'x-oss-security-token': stsToken.value.securityToken,
        key: objectKey,
        success_action_status: 200
    }

    return new Promise((resolve, reject) => {
        const host = "https://" + stsToken.value.bucket +
            "." + stsToken.value.region + ".aliyuncs.com"
        uni.uploadFile({
            url: host,
            filePath,
            name: 'file',
            formData,
            success: (res) => {
                if (res.statusCode === 200) {
                    resolve(`${CDN_HOST}/${objectKey}`)
                } else {
                    reject(new Error('上传失败'))
                }
            },
            fail: reject
        })
    })
}